<?php

namespace App\Services\Wxpay;

use Exception;
use WxPayConfig;


class Wxpay
{
    public function __construct()
    {
        $this->autoload();
    }

    //app支付
    public function app($body, $order_no, $amount, $notify_url)
    {
        require_once 'libs/WxPay.Config.App.php';

        $result = $this->unifiedorder($body, $order_no, $amount, $notify_url, 'APP');

        $this->checkResult($result);

        return $this->appPaySign($result);
    }

    //微信退款
    public function wxRefund($order,$type,$refund_desc="",$notify_url=""){
        require_once "libs/WxPay.Config.$type.php";
        $input = new \WxPayRefund();
        $input->SetOut_trade_no($order->order_no);
        $input->SetTotal_fee(bcmul($order->amount,100));
        $input->SetRefund_fee(bcmul($order->amount,100));
        $input->SetOut_refund_no(WxPayConfig::MCHID.date("YmdHis").rand(100,999));
        $input->SetOp_user_id(WxPayConfig::MCHID);
        $input->SetNotify_url($notify_url);
        $input->SetRefund_desc($refund_desc);
        return \WxPayApi::refund($input);
        
    }
    //扫码支付
    // ["appid"]=> string(18) "wxc00eb5b4209a7fac" 
    // ["code_url"]=> string(35) "weixin://wxpay/bizpayurl?pr=ESRX9jw" 
    // ["mch_id"]=> string(10) "1486275522" 
    // ["nonce_str"]=> string(16) "TB42l023BnYnffdM" 
    // ["prepay_id"]=> string(36) "wx20170927140131cd33f9225b0646111588" 
    // ["result_code"]=> string(7) "SUCCESS" 
    // ["return_code"]=> string(7) "SUCCESS" 
    // ["return_msg"]=> string(2) "OK" 
    // ["sign"]=> string(32) "2CE3F505E39FECA43F2DC22D2D5A7324" 
    // ["trade_type"]=> string(6) "NATIVE" 
    public function native($body, $order_no, $amount, $notify_url)
    {
        require_once 'libs/WxPay.Config.Native.php';

        $result = $this->unifiedorder($body, $order_no, $amount, $notify_url, 'NATIVE');
        $this->checkResult($result);

        return [
            'code_url'  => $result['code_url'],
            'prepayid'  => $result['prepay_id'],
            // 'appid'     => $result['appid'],
            // 'mch_id'    => $result['mch_id'],
            // 'nonce_str' => $result['nonce_str'],
            // 'sign'      => $result['sign'],
        ];
    }

    public function h5($body, $order_no, $amount, $notify_url)
    {
        require_once 'libs/WxPay.Config.Native.php';

        $result = $this->unifiedorder($body, $order_no, $amount, $notify_url, 'MWEB');

        $this->checkResult($result);

        return [
            'mweb_url'=> $result['mweb_url'],
            'prepayid'=> $result['prepay_id'],
        ];
    }

    public function js($body, $order_no, $amount, $notify_url, $openid)
    {
        require_once 'libs/WxPay.Config.Native.php';

        $result = $this->unifiedorder($body, $order_no, $amount, $notify_url, 'JSAPI', $openid);

        $this->checkResult($result);

        return array_merge($result, [
            'params'=> $this->jsapiPaySign($result),
        ]);
    }

    protected function unifiedorder($body, $order_no, $amount, $notify_url, $trade_type, $openid='')
    {
        $input = new \WxPayUnifiedOrder();
        $input->SetBody($body);
        // $input->SetAttach("test");
        $input->SetOut_trade_no($order_no);
        $input->SetTotal_fee($amount);
        $input->SetTime_start(date("YmdHis"));
        //$input->SetTime_expire(date("YmdHis", time() + 600));

        // $input->SetGoods_tag("test");
        $input->SetNotify_url($notify_url);
        $input->SetTrade_type($trade_type);
        if ( $trade_type=='NATIVE' ){
            $input->SetProduct_id($order_no);
        }
        if ( $trade_type=='JSAPI' ){
            $input->SetOpenid( $openid );
        }

        return \WxPayApi::unifiedOrder($input);
    }

    public function notify($callback, $logger=null)
    {
        try{
            $msg = null;
            $notify = new WxpayNotify;
            $notify->Handle($callback);
            return true;
        }catch(Exception $e){
            $notify->replyFailNotify($e->getMessage());
            if ( $logger ){
                call_user_func($logger, $e);
            }
            return false;
        }
    }

    private function autoload()
    {
        require_once 'libs/WxPay.Api.php';
        require_once 'libs/WxPay.Data.php';
        require_once 'libs/WxPay.Exception.php';
        require_once 'libs/WxPay.Notify.php';
        require_once 'libs/WxPay.Config.php';
    }

    private function appPaySign($result)
    {
        $data = [
            'appid'     => $result['appid'],
            'partnerid' => $result['mch_id'],
            'prepayid'  => $result['prepay_id'],
            'package'   => 'Sign=WXPay',
            'noncestr'  => $result['nonce_str'],
            'timestamp' => time(),
        ];

        $wxpayresults = new \WxPayResults;
        $wxpayresults->FromArray($data);
        $wxpayresults->SetSign();

        return $wxpayresults->GetValues();
    }

    private function jsapiPaySign($result)
    {
        $data = [
            'appId'     => $result['appid'],
            'signType'  => 'MD5',
            'package'   => 'prepay_id='.$result['prepay_id'],
            'nonceStr'  => $result['nonce_str'],
            'timeStamp' => (string)time(),
        ];

        $wxpayresults = new \WxPayResults;
        $wxpayresults->FromArray($data);
        $data['paySign'] = $wxpayresults->MakeSign();

        return $data;//$wxpayresults->GetValues();
    }

    private function checkResult($result)
    {
        if ( $result['return_code'] !== 'SUCCESS' ){
            throw new Exception($result['return_msg'], 1);
        }

        if ( $result['result_code'] !== 'SUCCESS' ){
            throw new Exception(sprintf('code: %d, error: %s', $result['err_code'], $result['err_code_des']), 1);
        }
    }
}